from django.test import TestCase
from django_acl.models import *

class AclTestCase(TestCase):
  fixtures = [ 'starwars_users.json', 'starwars_acl.json' ]
  
  permission_matrix = (
    # ARO,  name, cockpit, guns, lounge, engines
    (7 , 'luke', 3, 3, 3, -1), # Jedi in the cockpit and explicit on guns
    (5 , 'chewie', 2, 2, 3, -3), # Chewie can't be trusted in the engine room
    (11, 'obi-wan', 3, -1, 3, -1), # Jedi in the cockpit
    (13, 'r2d2', -1, 3, 3, 3), # as a member of engineers
    (14, 'r2d2', -1, -1, 3, -1), # as a member of passengers
    (4 , 'han', 2, 2, 3, 2), # can do everything
  )
  
  user_matrix = (
    # uid,  username, cockpit, guns, lounge, engines
    (2, 'han', True, True, True, True),
    (3, 'luke', True, True, True, False),
    (4, 'chewie', True, True, True, False),
    (5, 'leya', False, False, True, False),
    (6, 'r2d2', False, True, True, True), # combination of two entries
    (7, 'obi-wan', True, False, True, False),
    (8, 'c3po', False, False, True, False),
  )
  
  def setUp(self):
    self.places = (
      ACO.objects.get(pk=3), # cockpit
      ACO.objects.get(pk=4), # guns
      ACO.objects.get(pk=5), # lounge
      ACO.objects.get(pk=6), # engines
    )
  
  def testPermissions(self):
    for test in self.permission_matrix:
      aro = ARO.objects.get(pk=test[0])
      self.assertEqual(str(aro), test[1])
      for i in range(4):
        result = check_permission(aro, self.places[i], 5)
        self.assertEqual(result, test[2+i], "Expected %s for %s in %s, got %s" % (test[2+i], aro, self.places[i], result))
        
  def testUserPermissions(self):
    
    for test in self.user_matrix:
      user = User.objects.get(pk=test[0])
      self.assertEqual(str(user), test[1])
      for i in range(4):
        result = has_permission(user, self.places[i], 'can_enter')
        self.assertEqual(result, test[2+i], "Expected %s for %s in %s, got %s" % (test[2+i], user, self.places[i], result))
  
  def testInconsistentAcl(self):
    ARO.objects.create(user_id=4, parent_id=9) # adding chewie to engineers
    chewie = User.objects.get(pk=4)
    with self.assertRaises(Exception) as cm:
      has_permission(chewie, self.places[3], 'can_enter')
    self.assertEqual(cm.exception.message, "Inconsistent ACL for user chewie on engines")
  
  def testPaths(self):
    self.assertEqual(repr(ACO.objects.match_path([ 'bad', 'path' ])), '<ACO: *>')
    self.assertEqual(repr(ACO.objects.match_path([ 'millenium_falcon', 'extra', 'path' ])), '<ACO: millenium_falcon>')
    self.assertEqual(repr(ACO.objects.match_path([ 'millenium_falcon', 'engines' ])), '<ACO: engines>')
    self.assertEqual(repr(ACO.objects.match_path([ 'millenium_falcon', 'engines', 'extra' ])), '<ACO: engines>')
  
  def testUserMapping(self):
    chewie = User.objects.get(pk=4)
    self.assertEqual(repr(chewie.get_access_request_objects()), '[<ARO: chewie>]')
    leya = User.objects.get(pk=5)
    self.assertEqual(repr(leya.get_access_request_objects()), '(<ARO: [ users ]>,)')
    r2d2 = User.objects.get(pk=6)
    self.assertEqual(repr(r2d2.get_access_request_objects()), '[<ARO: r2d2>, <ARO: r2d2>]')
  
  def testNamedPermissions(self):
    chewie = User.objects.get(pk=4)
    self.assertEqual(has_named_permission(chewie, 'millenium_falcon.can_enter'), True)
    self.assertEqual(has_named_permission(chewie, 'millenium_falcon.cockpit.can_enter'), True)
    self.assertEqual(has_named_permission(chewie, 'millenium_falcon.engines.can_enter'), False)
    